#! usr/bin/python3
# coding=utf-8
# @Time: 2025/9/20 
# @Author: GaoSheng
import re

from base.utils import set_or_update_node, smart_payload


def api(rule, method="post", is_json_req=True, hooks=None, **kwargs):
    """
    同时支持restful风格接口调用

    :param rule: 接口地址,如果是restful接口,则: /query/<id>/
    :param method: 请求方式 get/post/option ...
    :param is_json_req: 是否是json请求,如果传True，传给requests.request为 json=payload
    :param hooks: [function(client: BaseClient, method: str, request: requests.request入参)]
    :param kwargs: 具体参考BaseClient._call_api的请求参数
    :return:
    """

    def wrapper(func):
        def _wrapper(self, *fargs, **fkwargs):
            payload = smart_payload(func)(self, *fargs, **fkwargs)

            # parse rule
            c = re.compile(r'<\S*?>')
            endpoint = rule
            paths = c.findall(endpoint)
            for path in paths:
                tp = path[1:-1]
                if tp not in payload:
                    raise ValueError("invalid restful api rule")
                else:
                    endpoint = endpoint.replace(path, str(payload.pop(tp)))  # url path must be string

            req_kwargs = kwargs.pop("req_kwargs", {})
            if method.upper() == "GET":
                set_or_update_node(req_kwargs, 'params', payload)
            elif is_json_req:
                set_or_update_node(req_kwargs, 'json', payload)
            else:
                set_or_update_node(req_kwargs, 'data', payload)

            if hooks is not None:
                if callable(hooks):
                    # 用于提取Client接口的公共行为，比如将`self.token`写入请求头
                    # def request_with_token(client, method, request):
                    #     request['headers'] = {"Authentication": getattr(client, "token")}
                    hooks(self, method, req_kwargs, endpoint=endpoint)
                else:
                    for hook in hooks:
                        hook(self, method, req_kwargs, endpoint=endpoint)

            return self._call_api(endpoint, method, req_kwargs)
        return _wrapper
    return wrapper